package com.lx.service.impl;

import com.lx.dao.ProductDao;
import com.lx.dao.ProductEsRepository;
import com.lx.entity.Product;
import com.lx.service.ProductService;
import com.lx.util.PageInfo;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
@Transactional
public class ProductServiceImpl implements ProductService {
    @Autowired
    ProductDao productDao;
    @Autowired
    ProductEsRepository productEsRepository;
    @Autowired
    ElasticsearchRestTemplate esTemplate;

    @Override
    public List<Product> getAllProduct() {
        return productDao.selectAll();
    }

    @Override
    public PageInfo<Product> getPageInfo(Map<String, Object> params) {
        PageInfo<Product> pageInfo = new PageInfo<>();
        int pageNum = Integer.parseInt(params.get("pageNum").toString());
        int pageSize = Integer.parseInt(params.get("pageSize").toString());

        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();

        if (params.containsKey("name") && params.get("name") != null) {
            boolQueryBuilder.must(QueryBuilders.matchQuery("name", params.get("name")));
        }

        if (params.containsKey("createTime") && params.get("createTime") != null) {
            try {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                Date date = sdf.parse(params.get("createTime").toString());
                Date startDate = new Date(date.getTime() - 24 * 60 * 60 * 1000);
                Date endDate = new Date(date.getTime() + 24 * 60 * 60 * 1000);
                boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime")
                        .gte(startDate)
                        .lte(endDate));
            } catch (Exception e) {
                boolQueryBuilder.must(QueryBuilders.termQuery("createTime", params.get("createTime")));
            }
        }

        queryBuilder.withQuery(boolQueryBuilder);
        queryBuilder.withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC));

        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("name")
                .field("description")
                .preTags("<span style='color:red'>")
                .postTags("</span>");
        queryBuilder.withHighlightBuilder(highlightBuilder);
        queryBuilder.withPageable(PageRequest.of(pageNum - 1, pageSize));

        SearchHits<Product> hits = esTemplate.search(queryBuilder.build(), Product.class);
        List<Product> productList = new ArrayList<>(pageSize + 5);

        for (SearchHit<Product> hit : hits.getSearchHits()) {
            Product product = hit.getContent();
            Map<String, List<String>> highLightMap = hit.getHighlightFields();
            if (!highLightMap.isEmpty()) {
                List<String> nameList = highLightMap.get("name");
                if (nameList != null && !nameList.isEmpty()) {
                    product.setName(nameList.get(0));
                }
                List<String> descList = highLightMap.get("description");
                if (descList != null && !descList.isEmpty()) {
                    product.setDescription(descList.get(0));
                }
            }
            productList.add(product);
        }

        pageInfo.setPageNum(pageNum);
        pageInfo.setPageSize(pageSize);
        pageInfo.setTotalCount((int) hits.getTotalHits());
        pageInfo.setList(productList);

        return pageInfo;
    }

    @Override
    public PageInfo<Product> getPageInfoByCategory(Map<String, Object> params) {
        PageInfo<Product> pageInfo = new PageInfo<>();
        int pageNum = Integer.parseInt(params.get("pageNum").toString());
        int pageSize = Integer.parseInt(params.get("pageSize").toString());
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        //总共三个分类，根据type判断查询具体哪个级别下的哪个分类
        int type = Integer.parseInt(params.get("type").toString());
        String category = type == 1 ? "categoryLevel1Id" : (type == 2 ? "categoryLevel2Id" : "categoryLevel3Id");
        int categoryId = Integer.parseInt(params.get("categoryId").toString());
        queryBuilder.withQuery(QueryBuilders.termQuery(category, categoryId));
        queryBuilder.withSort(SortBuilders.fieldSort("createTime").order(SortOrder.DESC));
        queryBuilder.withPageable(PageRequest.of(pageNum - 1, pageSize));
        List<Product> productList = new ArrayList<>(pageSize + 5);
        SearchHits<Product> searchHits = esTemplate.search(queryBuilder.build(), Product.class);
        for (SearchHit<Product> hit : searchHits.getSearchHits()) {
            Product product = hit.getContent();
            productList.add(product);
        }
        pageInfo.setPageNum(pageNum);
        pageInfo.setPageSize(pageSize);
        pageInfo.setTotalCount((int) searchHits.getTotalHits());
        pageInfo.setList(productList);
        return pageInfo;
    }

    @Override
    public Product getProductById(Integer id) {
//        return productDao.selectById(id);
        //修改用es查询， 查询单个，不需要分页
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.termQuery("id", id));
        SearchHits<Product> hits = esTemplate.search(queryBuilder.build(), Product.class);
        return hits.getSearchHits().get(0).getContent();
    }

    @Override
    public boolean addProduct(Product product) {
        product.setCreateTime(new Date());
        int result = productDao.addProduct(product);
        if (result > 0) {
            productEsRepository.save(product);
            return true;
        }
        return false;
    }

    @Override
    public boolean updateProduct(Product product) {
        int result = productDao.updateProduct(product);
        if (result > 0) {
            productEsRepository.save(product);
            return true;
        }
        return false;
        /*productEsRepository.save(product);
        // 2. 创建新线程异步更新数据库
        new Thread(() -> {
            try {
                int result = productDao.updateProduct(product);
                if (result > 0) {
                    System.out.println("Database updated in background: " + product.getId());
                } else {
                    System.out.println("Database update affected 0 rows: " + product.getId());
                }
            } catch (Exception e) {
                System.out.println("Background database update failed:" + product.getId());
                // 简单重试一次
                try {
                    Thread.sleep(3000);
                    productDao.updateProduct(product);
                } catch (Exception ex) {
                    System.out.println("Retry also failed: " + product.getId());
                }
            }
        }).start();
        return true;*/
    }

    @Override
    public boolean updateProductNumber(Integer id, Integer number) {
        return productDao.updateProductNumber(id, number) == 1;
    }

    @Override
    public boolean deleteProduct(Integer id) {
//        return productDao.delProduct(id)>0;
//    }
        int result = productDao.delProduct(id);
        if (result > 0) {
            productEsRepository.deleteById(id.toString());
            return true;
        }
        return false;
    }
}
